<?php
/**
 * Copyright (c) 2008, Till Klampaeckel
 * 
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 * 
 *  * Redistributions of source code must retain the above copyright notice, this
 *    list of conditions and the following disclaimer.
 *  * Redistributions in binary form must reproduce the above copyright notice, this
 *    list of conditions and the following disclaimer in the documentation and/or
 *    other materials provided with the distribution.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * PHP Version 5
 *
 * @category   Net
 * @package    Net_DNS2
 * @subpackage Net_DNS2_Header
 * @author     Eric Kilfoil <edk@ypass.net>
 * @author     Marco Kaiser <bate@php.net>
 * @author     Florian Anderiasch <fa@php.net>
 * @author     Till Klampaeckel <till@php.net>
 * @copyright  1997-2008 The respective owners.
 * @license    http://www.opensource.org/licenses/bsd-license.php The BSD License
 * @version    Release: @package_version@
 * @link       http://net-dns2.googlecode.com/
 */
 
/**
 * Net_DNS2_Abstract
 */
require_once 'Net/DNS2/Abstract.php';

/**
 * Object representation of the HEADER section of a DNS packet
 *
 * The Net_DNS2_Header class contains the values of a DNS packet.  It parses
 * the header of a DNS packet or can  generate the binary data
 * representation of the packet.  The format of the header is described in
 * RFC1035.
 *
 * @category   Net
 * @package    Net_DNS2
 * @subpackage Net_DNS2_Header
 * @author     Eric Kilfoil <edk@ypass.net>
 * @author     Marco Kaiser <bate@php.net>
 * @author     Florian Anderiasch <fa@php.net>
 * @author     Till Klampaeckel <till@php.net>
 * @copyright  1997-2008 The respective owners.
 * @license    http://www.opensource.org/licenses/bsd-license.php The BSD License
 * @version    Release: @package_version@
 * @link       http://net-dns2.googlecode.com/
 */
class Net_DNS2_Header extends Net_DNS2_Abstract
{
    /**
     * The packet's request id
     *
     * The request id of the packet represented as  a 16 bit integer.
     */
    var $id;
    
    /**
     * The QR bit in a DNS packet header
     *
     * The QR bit as described in RFC1035.  QR is set to 0 for queries, and
     * 1 for repsones.
     */
    var $qr;
    
    /**
     * The OPCODE name of this packet.
     *
     * The string value (name) of the opcode for the DNS packet.
     */
    var $opcode;
    
    /**
     * The AA (authoritative answer) bit in a DNS packet header
     *
     * The AA bit as described in RFC1035.  AA is set to  1 if the answer
     * is authoritative.  It has no meaning if QR is set to 0.
     */
    var $aa;
    
    /**
     * The TC (truncated) bit in a DNS packet header
     *
     * This flag is set to 1 if the response was truncated.  This flag has
     * no meaning in a query packet.
     */
    var $tc;
    
    /**
     * The RD (recursion desired) bit in a DNS packet header
     *
     * This bit should be set to 1 in a query if recursion  is desired by
     * the DNS server.
     */
    var $rd;
    
    /**
     * The RA (recursion available) bit in a DNS packet header
     *
     * This bit is set to 1 by the DNS server if the server is willing to
     * perform recursion.
     */
    var $ra;
    
    /**
     * The RCODE name for this packet.
     *
     * The string value (name) of the rcode for the DNS packet.
     */
    var $rcode;
    
    /**
     * Number of questions contained within the packet
     *
     * 16bit integer representing the number of questions in the question
     * section of the DNS packet.
     *
     * @var integer $qdcount
     * @see Net_DNS2_Question class
     */
    var $qdcount;
    /**
     * Number of answer RRs contained within the packet
     *
     * 16bit integer representing the number of answer resource records
     * contained in the answer section of the DNS packet.
     *
     * @var integer $ancount
     * @see Net_DNS2_RR class
     */
    var $ancount;
    /**
     * Number of authority RRs within the packet
     *
     * 16bit integer representing the number of authority (NS) resource
     * records  contained in the authority section of the DNS packet.
     *
     * @var integer $nscount
     * @see Net_DNS2_RR class
     */
    var $nscount;
    /**
     * Number of additional RRs within the packet
     *
     * 16bit integer representing the number of additional resource records
     * contained in the additional section of the DNS packet.
     *
     * @var integer $arcount
     * @see Net_DNS2_RR class
     */
    var $arcount;

    /**
     * Initializes the default values for the Header object.
     * 
     * Builds a header object from either default values, or from a DNS
     * packet passed into the constructor as $data
     *
     * @param string $data  A DNS packet of which the header will be parsed.
     * 
     * @return object Net_DNS2_Header
     * @access public
     */
    public function __construct($data = '')
    {
        if (empty($data) !== true) {
            /*
             * The header MUST be at least 12 bytes.
             * Passing the full datagram to this constructor
             * will examine only the header section of the DNS packet
             */
            if (strlen($data) < 12) {
                return false;
            }

            $a = unpack('nid/C2flags/n4counts', $data);
            
            $this->id      = $a['id'];
            $this->qr      = ($a['flags1'] >> 7) & 0x1;
            $this->opcode  = ($a['flags1'] >> 3) & 0xf;
            $this->aa      = ($a['flags1'] >> 2) & 0x1;
            $this->tc      = ($a['flags1'] >> 1) & 0x1;
            $this->rd      = $a['flags1'] & 0x1;
            $this->ra      = ($a['flags2'] >> 7) & 0x1;
            $this->rcode   = $a['flags2'] & 0xf;
            $this->qdcount = $a['counts1'];
            $this->ancount = $a['counts2'];
            $this->nscount = $a['counts3'];
            $this->arcount = $a['counts4'];
            
        } else {
            
            $this->id      = Net_DNS2_Resolver::nextid();
            $this->qr      = 0;
            $this->opcode  = 0;
            $this->aa      = 0;
            $this->tc      = 0;
            $this->rd      = 1;
            $this->ra      = 0;
            $this->rcode   = 0;
            $this->qdcount = 1;
            $this->ancount = 0;
            $this->nscount = 0;
            $this->arcount = 0;
        }

        if (Net_DNS2::opcodesbyval($this->opcode)) {
            $this->opcode = Net_DNS2::opcodesbyval($this->opcode);
        }
        if (Net_DNS2::rcodesbyval($this->rcode)) {
            $this->rcode = Net_DNS2::rcodesbyval($this->rcode);
        }
    }

    /**
     * Returns a formatted string containing the properties of the header.
     *
     * @return string A formatted string containing the properties of the header.
     */
    public function string()
    {
        $retval = ';; id = ' . $this->id . "\n";
        if ($this->opcode == 'UPDATE') {
            
            $retval .= ';; qr = ' . $this->qr . '    ';
            $retval .= 'opcode = ' . $this->opcode . '    ';
            $retval .= 'rcode = ' . $this->rcode . "\n";
            $retval .= ';; zocount = ' . $this->qdcount . '  ';
            $retval .= 'prcount = ' . $this->ancount . '  ';
            $retval .= 'upcount = ' . $this->nscount . '  ';
            $retval .= 'adcount = ' . $this->arcount . "\n";
            
        } else {
            $retval .= ';; qr = ' . $this->qr . '    ';
            $retval .= 'opcode = ' . $this->opcode . '    ';
            $retval .= 'aa = ' . $this->aa . '    ';
            $retval .= 'tc = ' . $this->tc . '    ';
            $retval .= 'rd = ' . $this->rd . "\n";

            $retval .= ';; ra = ' . $this->ra . '    ';
            $retval .= 'rcode  = ' . $this->rcode . "\n";

            $retval .= ';; qdcount = ' . $this->qdcount . '  ';
            $retval .= 'ancount = ' . $this->ancount . '  ';
            $retval .= 'nscount = ' . $this->nscount . '  ';
            $retval .= 'arcount = ' . $this->arcount . "\n";
        }
        return $retval;
    }

    /**
     * Returns the binary data containing the properties of the header
     *
     * Packs the properties of the Header object into a binary string
     * suitable for using as the Header section of a DNS packet.
     *
     * @return string   binary representation of the header object
     */
    public function data()
    {
        $opcode = Net_DNS2::opcodesbyname($this->opcode);
        $rcode  = Net_DNS2::rcodesbyname($this->rcode);

        $byte2 = ($this->qr << 7)
            | ($opcode << 3)
            | ($this->aa << 2)
            | ($this->tc << 1)
            | ($this->rd);

        $byte3 = ($this->ra << 7) | $rcode;

        return pack('nC2n4',
            $this->id,
            $byte2,
            $byte3,
            $this->qdcount,
            $this->ancount,
            $this->nscount,
            $this->arcount);
    }
}
?>